/*
 * Copyright (C) 2004-2005, Universidade Federal de Campina Grande. All rights reserved.
 */
package org.epanetgrid.otimizacao.evaluators;

import java.io.Serializable;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;

import org.epanetgrid.otimizacao.objfunctions.ObjectiveFunction;
import org.epanetgrid.otimizacao.searchspace.IndividualEvaluator;
import org.epanetgrid.otimizacao.simulation.GradienteNaoConvergeOtimizacaoException;
import org.epanetgrid.otimizacao.simulation.SimulacaoNaoConvergeException;
import org.epanetgrid.otimizacao.simulation.Simulation;
import org.epanetgrid.resultado.ResultadoSimulacao;
import org.jheuristics.DefaultIndividual;
import org.jheuristics.Individual;


/**
 * Implementa��o Default de IndividualEvaluator. Para um indiv�duo, executa-se a simula��o deste
 * calcula as fun��es objetivo e seta no indiv�duo
 * @author Marcell Manfrin, marcell@ourgrid.org, Sep 13, 2005
 * @author Thiago Emmanuel Pereira da Cunha Silva, thiagoepdc@ourgrid.org, Sep 13, 2005
 */
public class DefaultIndividualEvaluator implements IndividualEvaluator, Serializable {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -1774402815500479132L;

	private Simulation simulacao;
	
	private ObjectiveFunction[] objectiveFunctions;

	private Map<Object, List> simulatedIndividuals = new WeakHashMap<Object, List>();
	
	/**
	 *
	 * @param simulacao Respons�vel por simular os indiv�duos
	 * @param objectiveFunctions Array de fun��es que avaliar�o o resultado da simula��o
	 */
	public DefaultIndividualEvaluator(Simulation simulacao, ObjectiveFunction[] objectiveFunctions) {
		this.simulacao = simulacao;
		this.objectiveFunctions = objectiveFunctions;
	}

	/*
	 * (non-Javadoc)
	 * @see org.smartpumping.otimizacao.searchspace.IndividualEvaluator#evaluate(org.jheuristics.Individual)
	 */
	public Individual evaluate(Individual individual) throws GradienteNaoConvergeOtimizacaoException {
		
		List gens = (List) individual.getGens();
		
		if(simulatedIndividuals.containsKey(gens)) {
			List dataApplicationResultante = simulatedIndividuals.get(gens);
			if(dataApplicationResultante == null) {
				throw new SimulacaoNaoConvergeException(" indiv�duo n�o convergiu");
			}
			individual.setDataApplication(dataApplicationResultante);
			return individual;
		}

		Object result = simulacao.simulate(gens);

		if (!(result instanceof ResultadoSimulacao)) {
			// TODO: ERROS MSG
			throw new IllegalArgumentException();
		}
		ResultadoSimulacao resultado = (ResultadoSimulacao) result;

	    List results = new LinkedList();
	    for (int i = 0; i < objectiveFunctions.length; i++) {
	    	Object evaluation = objectiveFunctions[i].evaluate(resultado);
	    	if (evaluation instanceof Collection) {
	    		results.addAll((Collection) evaluation);
	    	} else {
	    		results.add(evaluation);
	    	}
	    }

	    individual.setDataApplication(results);

	    List results2 = new LinkedList();
	    for (int i = 0; i < objectiveFunctions.length; i++) {
	    	Object evaluation = objectiveFunctions[i].evaluate(resultado);
	    	if (evaluation instanceof Collection) {
	    		results2.addAll((Collection) evaluation);
	    	} else {
	    		results2.add(evaluation);
	    	}
	    }

	    this.simulatedIndividuals.put(individual.getGens(), results2);

	    return individual;
	}

	private Individual copyIndividual(Individual individual, List dataApplication) {
		DefaultIndividual newIndividual = new DefaultIndividual(new LinkedList((List)individual.getGens()));
		newIndividual.setFitness(individual.getFitness());
		newIndividual.setDataApplication(dataApplication);
		return newIndividual;
	}

}
